package database.attset;

import java.util.ArrayList;
import java.util.Vector;

import database.fd.FunctionalDependency;
import database.fd.ListFunctionDependency;

@SuppressWarnings("serial")
public class SetAttribute extends Vector<Integer>{
	
	public SetAttribute() {}
	
    public SetAttribute(int firstAtt) {
         this.add(firstAtt);
    }

    public SetAttribute(SetAttribute cloneRelation) {
        for (int cl : cloneRelation) {
            this.add(cl);
        }
    }

    public SetAttribute(int firstAtt, SetAttribute cloneRelation) {
        this.add(firstAtt);

        for (int cl : cloneRelation) {
            this.add(cl);
        }
    }
	
	public void printSetAttribute() {
                if (this.size() > 0){
                        System.out.print("(");
                        for(int i = 0; i < this.size() - 1; i++) {
                                System.out.print(this.get(i));
                                System.out.print(", ");
                        }
                        System.out.print(this.get(this.size() - 1));
                        System.out.print(")");
                } else {
                        System.out.print("()");
                }
	}

    public boolean isSubSet(SetAttribute set) {
    	boolean isSubset = true;
        int n = this.size();
        int i = 0;
        while (isSubset && i<n){
            if(set.contains(this.get(i))){
                i++;
            } else {
                isSubset = false;
            }
        }
        return isSubset;
    }

    public boolean isRealSubSet(SetAttribute set) {
    	boolean isRealSubset = true;
        int n = this.size();
        int i = 0;
        while (isRealSubset && i<n){
            if(set.contains(this.get(i))){
                i++;
            } else {
                isRealSubset = false;
            }
        }

        if (isRealSubset==true && n==set.size()){
            isRealSubset = false;
        }

        return isRealSubset;
    }

    public boolean isEqual(SetAttribute set){
    	boolean isEqual = false;
        if (this.size() == set.size()){
            isEqual = this.isSubSet(set);
        }
        return isEqual;
    }

    public boolean isSuperSet(SetAttribute set) {
    	boolean isSupset = true;
        int n = set.size();
        int i = 0;
        while (isSupset && i < n){
            if(this.contains(set.get(i))){
                i++;
            } else {
                isSupset = false;
            }
        }
        return isSupset;
    }

    public SetAttribute intersection(SetAttribute set) {
    	SetAttribute setIntersection = new SetAttribute();
        for (int i=0; i<this.size(); i++){
            if (set.contains(this.get(i))){
                setIntersection.add(this.get(i));
            }
        }
        return setIntersection;    
    }

    public SetAttribute union(SetAttribute set) {
    	SetAttribute setUnion = (SetAttribute)this.clone();
        int n = set.size();
        for (int i = 0; i < n; i++){
            if (!setUnion.contains(set.get(i))){
                setUnion.add(set.get(i));
            }
        }
        return setUnion;
    }

    public SetAttribute unionAll(SetAttribute set) {
    	SetAttribute setUnion = (SetAttribute)this.clone();
        int n = set.size();
        for (int i = 0; i < n; i++){
            setUnion.add(set.get(i));
        }

        return setUnion;
    }

    public SetAttribute difference(SetAttribute set) {
    	SetAttribute setDiff = (SetAttribute)this.clone();
        int n = set.size();
        for (int i = 0; i < n; i++){
            if (setDiff.contains(set.get(i))){
                setDiff.remove(set.get(i));
            }
        }

        return setDiff;
    }


    // cai ham getClosure se khong lam thay doi ListFd
    public SetAttribute getClosure(ListFunctionDependency listFd) {
        listFd = (ListFunctionDependency) listFd.clone();
        return getClosure_Extra(listFd);
    }

    // dung ham nay thi Fd se bi thay doi
    public SetAttribute getClosure_Extra(ListFunctionDependency listFd) {
    	listFd = (ListFunctionDependency) listFd.clone();
        boolean isMore = false;
        SetAttribute closure = (SetAttribute)this.clone();

        do {
            isMore = false;
            int i = 0;
            while (i < listFd.size()){
                FunctionalDependency fd = listFd.get(i);
                if (closure.isSuperSet(fd.getLeft())){
                    int old_size = closure.size();
                    int new_size = 0;
                    closure = closure.union(fd.getRight());
                    new_size = closure.size();
                    // hoho - lieu mang
                    // TODO deo hieu. giai thich
                    // cai Fd nao xet roi thi tau remove
                    listFd.remove(i);
                    if (old_size < new_size){
                        isMore = true;
                    }
                } else {
                    i++;
                }
            }
        } while (isMore);

        return closure;
    }
    
    public ArrayList<SetAttribute> getListMaxSubset() {
        ArrayList<SetAttribute> listSubSet = new ArrayList<SetAttribute>();
        for (int att : this) {
            SetAttribute subSet = (SetAttribute) this.clone();
            subSet.remove(Integer.valueOf(att));
            listSubSet.add(subSet);
        }
        return listSubSet;
    }
    
    /*
     * ham nay se lay tat ca cac sub set cua relation
     * vi du: ABCD -> ABC, ABD, ACD, BCD, AB, AC, AD, BC, BD, CD, A, B, C, D
     */
    public ArrayList<SetAttribute> listSubSetAttribute(SetAttribute set) {
        ArrayList<SetAttribute> listSubSet = new ArrayList<SetAttribute>();

        if(set.size() == 0 || set.size() == 1) {
            return listSubSet;
        }

        if(set.size() == 2) {
            for (int attIndex : set) {
            	SetAttribute tmpRelation = new SetAttribute();
                tmpRelation.add(attIndex);
                listSubSet.add(tmpRelation);
            }
            return listSubSet;
        }

        SetAttribute cloneRelation = (SetAttribute) set.clone();

        int indextFirstAtt = cloneRelation.get(0);

        cloneRelation.remove(0);

        ArrayList<SetAttribute> listSubSetOfClone = set.listSubSetAttribute(cloneRelation);

        listSubSet.add(new SetAttribute(indextFirstAtt));

        listSubSet.add(new SetAttribute(cloneRelation));

        for(SetAttribute tmp : listSubSetOfClone) {
            listSubSet.add(new SetAttribute(tmp));
            listSubSet.add(new SetAttribute(indextFirstAtt, tmp));
        }

        return listSubSet;
    }
}
